`timescale 1ns/1ps
module booth_fsm
       # (parameter DATAWIDTH = 8)
       (
           input clk,
           input rstn,
           input en,
           input [DATAWIDTH - 1: 0] multiplier,
           input [DATAWIDTH - 1: 0] multiplicand,
           output reg done,
           output reg [2 * DATAWIDTH - 1: 0] product
       );


parameter IDLE = 2'b00,
          ADD = 2'b01,
          SHIFT = 2'b11,
          OUTPUT = 2'b10;

reg [1: 0] current_state, next_state;  // state registers.
reg [2 * DATAWIDTH + 1: 0] a_reg, s_reg, p_reg, sum_reg;  // computational values.
reg [DATAWIDTH - 1: 0] iter_cnt;                   // iteration count for determining when done.
wire [DATAWIDTH: 0] multiplier_neg;             // negative value of multiplier


always @(posedge clk or negedge rstn)
	if (!rstn)
		current_state = IDLE;
	else
		current_state <= next_state;

// state transform
always @( * )
	begin
		next_state = 2'bx;
		case (current_state)
			IDLE :
				if (en)
					next_state = ADD;
				else
					next_state = IDLE;
			ADD :
				next_state = SHIFT;
			SHIFT :
				if (iter_cnt == DATAWIDTH)
					next_state = OUTPUT;
				else
					next_state = ADD;
			OUTPUT:
				next_state = IDLE;
		endcase
	end

// negative value of multiplier.
assign multiplier_neg = -{multiplier[DATAWIDTH - 1], multiplier};
// algorithm implemenation details.
always @(posedge clk or negedge rstn)
	begin
		if (!rstn)
			begin
				{a_reg, s_reg, p_reg, iter_cnt, done, sum_reg, product} <= 0;
			end
		else
			begin
				case (current_state)
					IDLE :
						begin
							a_reg <= {multiplier[DATAWIDTH - 1], multiplier, {(DATAWIDTH + 1){1'b0}}};
							s_reg <= {multiplier_neg, {(DATAWIDTH + 1){1'b0}}};
							p_reg <= {{(DATAWIDTH + 1){1'b0}}, multiplicand, 1'b0};
							iter_cnt <= 0;
							done <= 1'b0;
						end
					ADD :
						begin
							case (p_reg[1: 0])
								2'b01 :
									sum_reg <= p_reg + a_reg; // + multiplier
								2'b10 :
									sum_reg <= p_reg + s_reg; // - multiplier
								2'b00, 2'b11 :
									sum_reg <= p_reg;       // nop
							endcase
							iter_cnt <= iter_cnt + 1;
						end
					SHIFT :
						begin
							p_reg <= {sum_reg[2 * DATAWIDTH + 1], sum_reg[2 * DATAWIDTH + 1: 1]}; // right shift
						end
					OUTPUT :
						begin
							product <= p_reg[2 * DATAWIDTH: 1];
							done <= 1'b1;
						end
				endcase
			end
	end

endmodule


//自己写的
`timescale 1ns/1ps
module booth_fsm
       # (parameter DATAWIDTH = 8)
       (
           input clk,
           input rst_n,
        //    input en,
           input signed [DATAWIDTH - 1: 0] multiplier,
           input signed [DATAWIDTH - 1: 0] multiplicand,
           output reg done,
           output reg signed [2 * DATAWIDTH - 1: 0] product
       );

reg [1: 0] state, state_next;
parameter idle = 2'b00;
parameter shift = 2'b01;
parameter add = 2'b10;
parameter out = 2'b11;
reg [$clog2(DATAWIDTH): 0] cnt;

reg signed [ DATAWIDTH * 2 : 0] q_reg;
reg [ DATAWIDTH * 2 : 0] s_reg,s_reg1;
// wire signed [DATAWIDTH-1:0] multiplicand_b=multiplicand>0?multiplicand:{multiplicand[DATAWIDTH-1],~multiplicand[DATAWIDTH-2:0]+1'b1};

always@(posedge clk or negedge rst_n)
	begin
		if (!rst_n)
			state <= idle;
		else
			state <= state_next;
	end

always@( * )
	begin
		if (!rst_n)
			state_next = idle;
		else
			case (state)
				idle:
					begin
						// q_reg = {{(DATAWIDTH - 1){multiplier[DATAWIDTH - 1]}}, multiplicand, 1'b0};
						// s_reg = {{(DATAWIDTH - 1){multiplier[DATAWIDTH - 1]}}, multiplicand, 1'b0};
						state_next = add;
					end
				add:
					begin
						state_next = shift;
					end
				shift:
					begin
						if (cnt == DATAWIDTH)
							state_next = out;
						else
							state_next = add;
					end
				out:
					state_next = idle;
			endcase
	end


always@(posedge clk or negedge rst_n)
	begin
		if (!rst_n)
			begin
				q_reg <= 0;
				s_reg <= 0;
				done <= 1'b0;
				product <= 0;
				cnt <=0;
			end
		else
			begin
				case (state)
					idle:
						begin
							q_reg <= {{(DATAWIDTH){1'b0}}, multiplicand, 1'b0};
							s_reg<= {multiplier,{(DATAWIDTH+1){1'b0}}};
						end
					add:
						begin
							cnt = cnt + 1'b1;
							case (q_reg[1: 0])
								2'b10:
									q_reg <= q_reg - s_reg;
								2'b01:
									q_reg <= q_reg + s_reg;
								2'b00, 2'b11:
									q_reg <= q_reg;
							endcase
						end
					shift:
						begin
							q_reg <= q_reg >>> 1;
						end
					out:
						begin
							done <= 1'b1;
							product <= q_reg[DATAWIDTH * 2 : 1];
						end

				endcase
			end
	end

endmodule